package com.xjrh.traintravel.collector.netty.handler;

import com.xjrh.common.core.utils.ObjectUtils;
import com.xjrh.traintravel.collector.common.CRC16M;
import com.xjrh.traintravel.collector.common.CodeConvertor;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementCommandEnum;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementConstant;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementStructure;
import com.xjrh.traintravel.collector.netty.command.fault.CommonFault;
import com.xjrh.traintravel.collector.netty.command.fault.EquipmentFault;
import com.xjrh.traintravel.collector.netty.command.fault.PartFault;
import com.xjrh.traintravel.collector.netty.command.fault.PartFaultDetails;
import com.xjrh.traintravel.collector.netty.command.station.TravelStationRegionData;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.List;

/**
 * 故障上报-指令处理类
 *
 * @author snps
 * @create 2022-04-20 8:31
 * @describe
 **/
@Component
@Slf4j
public class FaultHandler extends BaseAgreementHandler {

    // 单个故障详细信息的协议数据长度
    private static final int FAULT_DETAILS_DATA_LENGTH = 16;
    private static final int FAULT_DETAILS_DATA_LENGTH_OLD = 14;


    /**
     * 收到：设备异常
     *
     * @param equipmentId
     * @param data
     * @return EquipmentFault
     */
    public EquipmentFault getEquipmentFault(String equipmentId, String data) {
        EquipmentFault equipmentFault = new EquipmentFault();
        equipmentFault.setEquipmentId(equipmentId);
        equipmentFault.setCommonNo(data.substring(0, 2));
        equipmentFault.setHostFaultStatus(data.substring(2, 6));
        equipmentFault.setDspFault(data.substring(6, 10));
        equipmentFault.setFront1Fault(data.substring(10, 12));
        equipmentFault.setFront1Type(data.substring(12, 14));
        equipmentFault.setFront1Sensor(data.substring(14, 16));
        equipmentFault.setFront2Fault(data.substring(16, 18));
        equipmentFault.setFront2Type(data.substring(18, 20));
        equipmentFault.setFront2Sensor(data.substring(20, 22));
        equipmentFault.setFront3Fault(data.substring(22, 24));
        equipmentFault.setFront3Type(data.substring(24, 26));
        equipmentFault.setFront3Sensor(data.substring(26, 28));
        equipmentFault.setFront4Fault(data.substring(28, 30));
        equipmentFault.setFront4Type(data.substring(30, 32));
        equipmentFault.setFront4Sensor(data.substring(32));
        return equipmentFault;
    }

    /**
     * 回复，收到：设备异常状态
     *
     * @param agreement
     * @param channel
     */
    public void reply01(AgreementStructure agreement, Channel channel) {
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_8D.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(CodeConvertor.intToHexString(1, 1));
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 长度(2)
        replyAgreement.setLen(CodeConvertor.intToHexString(2, 2));
        // 数据(N)
        replyAgreement.setData("0101");
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        super.sendCommand(replyAgreement);
    }

    /**
     * 回复，收到：检测故障
     *
     * @param agreement
     * @param channel
     */
    public void reply02(AgreementStructure agreement, Channel channel) {
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_8D.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(CodeConvertor.intToHexString(1, 1));
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 长度(2)
        replyAgreement.setLen(CodeConvertor.intToHexString(2, 2));
        // 数据(N)
        replyAgreement.setData("0201");
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        super.sendCommand(replyAgreement);
    }

    /**
     * 回复，收到：站点信息
     *
     * @param agreement
     * @param channel
     */
    public void reply03(AgreementStructure agreement, Channel channel) {
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_8D.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(CodeConvertor.intToHexString(1, 1));
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 长度(2)
        replyAgreement.setLen(CodeConvertor.intToHexString(2, 2));
        // 数据(N)
        replyAgreement.setData("0301");
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        super.sendCommand(replyAgreement);
    }

    /**
     * 收到通用异常
     *
     * @param equipmentId
     * @param data
     * @return
     */
    public CommonFault getCommonFault(String equipmentId, String data) {
        CommonFault commonFault = new CommonFault();
        commonFault.setEquipmentId(equipmentId);
        commonFault.setCommonNo(data.substring(0, 2));
        commonFault.setFaultCode(data.substring(2));
        return commonFault;
    }


    /**
     * 收到：算法检测故障
     */
    public PartFault getPartFault(String equipmentId, String data) {
        PartFault partFault = new PartFault();
        partFault.setEquipmentId(equipmentId);
        partFault.setCommonNo(data.substring(0, 2));
        // 故障分类
        partFault.setFaultType(Integer.parseInt(data.substring(2, 4), 16));
        // 时间（年月日时分秒）
        int timeValue = 0;
        StringBuilder sbuTime = new StringBuilder();
        sbuTime.append((timeValue = Integer.parseInt(data.substring(4, 6), 16)) >= 10 ? timeValue : "0"+timeValue);
        sbuTime.append((timeValue = Integer.parseInt(data.substring(6, 8), 16)) >= 10 ? timeValue : "0"+timeValue);
        sbuTime.append((timeValue = Integer.parseInt(data.substring(8, 10), 16)) >= 10 ? timeValue : "0"+timeValue);
        sbuTime.append((timeValue = Integer.parseInt(data.substring(10, 12), 16)) >= 10 ? timeValue : "0"+timeValue);
        sbuTime.append((timeValue = Integer.parseInt(data.substring(12, 14), 16)) >= 10 ? timeValue : "0"+timeValue);
        sbuTime.append((timeValue = Integer.parseInt(data.substring(14, 16), 16)) >= 10 ? timeValue : "0"+timeValue);
        partFault.setTime(sbuTime.toString());
        // 省略：段、列、车
        // 转向架、设备（前置）、传感器
        partFault.setCom(Integer.parseInt(data.substring(34, 36), 16));
        partFault.setFrontType(Integer.parseInt(data.substring(36, 38), 16));
        partFault.setFrontAccess(Integer.parseInt(data.substring(38, 40), 16));
        // 2024-10-12 修改协议实现
        // 故障数量
        partFault.setFaultCount(Integer.parseUnsignedInt(data.substring(40, 42), 16));
        // log.warn("检测结果数量：{}", partFault.getFaultCount());
        // 检测结果数量-详细信息
        partFault.setFaultDetails(data.substring(42));
        // log.warn("检测结果数量-详细信息：{}", partFault.getFaultDetails());
        if (ObjectUtils.isNotEmpty(partFault.getFaultDetails())) {
            //log.warn("检测结果数量-详细信息-长度：{}", partFault.getFaultDetails().length());
            // log.warn("检测结果数量-详细信息-数量：{}", partFault.getFaultDetails().length() / FAULT_DETAILS_DATA_LENGTH);
            List<PartFaultDetails> lstPartFaultDetail = new ArrayList<>(partFault.getFaultCount());
            int index = 0;
            for (int i=0; i<partFault.getFaultCount(); i++) {
                // TODO 2024-11-24 通过"故障详细信息长度判断是新、旧协议"
                if (partFault.getFaultDetails().length() % FAULT_DETAILS_DATA_LENGTH == 0) {
                    // TODO 新协议
                    // log.warn("新协议...");
                    String details = partFault.getFaultDetails().substring(index, index + FAULT_DETAILS_DATA_LENGTH);
                    // log.warn("PartFaultDetails: {}", details);
                    PartFaultDetails partFaultDetails = new PartFaultDetails();
                    partFaultDetails.setFaultPointNo(details.substring(0, 2));
                    // partFaultDetails.setGearboxBearingType(details.substring(2, 4));
                    partFaultDetails.setWheelJumpingFactor(Integer.parseInt(details.substring(2, 4), 16));
                    partFaultDetails.setFaultLevel(Integer.parseInt(details.substring(4, 6), 16));
                    partFaultDetails.setFaultDbValue(Integer.parseInt(details.substring(6, 14), 16));
                    partFaultDetails.setPolygonLevel(Integer.parseInt(details.substring(14), 16));
                    lstPartFaultDetail.add(partFaultDetails);
                    index+=FAULT_DETAILS_DATA_LENGTH;
                } else {
                    // TODO 旧协议
                    // log.warn("旧协议...");
                    log.warn(partFault.getFaultDetails());
                    String details = partFault.getFaultDetails().substring(index, index + FAULT_DETAILS_DATA_LENGTH_OLD);
                    // log.warn("PartFaultDetails: {}", details);
                    PartFaultDetails partFaultDetails = new PartFaultDetails();
                    partFaultDetails.setFaultPointNo(details.substring(0, 2));
                    // partFaultDetails.setGearboxBearingType(details.substring(2, 4));
                    partFaultDetails.setWheelJumpingFactor(0);
                    partFaultDetails.setFaultLevel(Integer.parseInt(details.substring(4, 6), 16));
                    partFaultDetails.setFaultDbValue(Integer.parseInt(details.substring(6, 14), 16));
                    partFaultDetails.setPolygonLevel(0);
                    lstPartFaultDetail.add(partFaultDetails);
                    index+=FAULT_DETAILS_DATA_LENGTH_OLD;
                }
            }
            partFault.setDetails(lstPartFaultDetail);
        }

        // 返回
        return partFault;
    }

    /**
     * 回复，收到：算法检测故障
     *
     * @param agreement
     * @param channel
     */
    public void reply04(AgreementStructure agreement, Channel channel) {
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_8D.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(CodeConvertor.intToHexString(1, 1));
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 长度(2)
        replyAgreement.setLen(CodeConvertor.intToHexString(2, 2));
        // 数据(N)
        replyAgreement.setData("0401");
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        super.sendCommand(replyAgreement);
    }

    /**
     * 收到：站点运行信息，构造返回数据
     *
     * @param equipmentId 主机设备标识
     * @param data 协议数据
     * @return TravelStationRegionData
     */
    public TravelStationRegionData getTravelStationRegionData(String equipmentId, String data) {
        TravelStationRegionData travelStationRegionData = new TravelStationRegionData();
        travelStationRegionData.setEquipmentId(equipmentId);
        travelStationRegionData.setCommonNo(data.substring(0, 2));
        // 设置：出发站点编号
        travelStationRegionData.setStartStation(String.valueOf(Integer.parseInt(data.substring(2, 6), 16)));
        // 设置：到达站点编号
        travelStationRegionData.setEndStation(String.valueOf(Integer.parseInt(data.substring(6, 10), 16)));
        // 设置：出发时间
        int timeValue = 0;
        StringBuilder sbuStartTime = new StringBuilder("20");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(10, 12), 16)) >= 10 ? timeValue : "0"+timeValue).append("-");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(12, 14), 16)) >= 10 ? timeValue : "0"+timeValue).append("-");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(14, 16), 16)) >= 10 ? timeValue : "0"+timeValue).append(" ");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(16, 18), 16)) >= 10 ? timeValue : "0"+timeValue).append(":");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(18, 20), 16)) >= 10 ? timeValue : "0"+timeValue).append(":");
        sbuStartTime.append((timeValue = Integer.parseInt(data.substring(20, 22), 16)) >= 10 ? timeValue : "0"+timeValue);
        travelStationRegionData.setStartTime(sbuStartTime.toString());
        // 设置：到达时间
        StringBuilder sbuEndTime = new StringBuilder("20");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(22, 24), 16)) >= 10 ? timeValue : "0"+timeValue).append("-");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(24, 26), 16)) >= 10 ? timeValue : "0"+timeValue).append("-");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(26, 28), 16)) >= 10 ? timeValue : "0"+timeValue).append(" ");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(28, 30), 16)) >= 10 ? timeValue : "0"+timeValue).append(":");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(30, 32), 16)) >= 10 ? timeValue : "0"+timeValue).append(":");
        sbuEndTime.append((timeValue = Integer.parseInt(data.substring(32), 16)) >= 10 ? timeValue : "0"+timeValue);
        travelStationRegionData.setEndTime(sbuEndTime.toString());

        // 返回
        return travelStationRegionData;
    }


    /**
     * 回复，收到：站点运行信息
     *
     * @param agreement
     * @param channel
     */
    public AgreementStructure reply0D(AgreementStructure agreement, Channel channel) {
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_8D.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(CodeConvertor.intToHexString(1, 1));
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 长度(2)
        replyAgreement.setLen(CodeConvertor.intToHexString(2, 2));
        // 数据(N)
        replyAgreement.setData("0D01");
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        super.sendCommand(replyAgreement);
        return replyAgreement;
    }


}